<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Y.App Using a Presenter</title>
</head>
<body>
    <h1>Y.App Using a Presenter</h1>

    <script id="t-user" type="text/x-handlebars-template">
    <ul>
        <li><b>Fullname:</b> {{fullname}}</li>
        <li><b>Username:</b> {{username}}</li>
    </ul>

    <p><a href="#/edit/">Edit User</a></p>
    </script>

    <script id="t-user-edit" type="text/x-handlebars-template">
    <form action="" method="POST">
        <fieldset>
            <legend>User Info</legend>

            <div>
            <label for="f-fullname">Fullname:</label>
            <input id="f-fullname" type="text" name="fullname" value="{{fullname}}" />
            </div>

            <div>
            <label for="f-username">Username:</label>
            <input id="f-username" type="text" name="username" value="{{username}}" />
            </div>
        </fieldset>

        <a href="#/">Cancel</a>
        <input type="submit" value="Save" />
    </form>
    </script>

    <script src="../../../../build/yui/yui.js"></script>
    <script>
    YUI({filter: 'raw'}).use('app', 'handlebars', function (Y) {

        // -- Presenter --------------------------------------------------------

        Y.Presenter = Y.Base.create('presenter', Y.Base, [], {

            viewType: Y.View,

            initializer: function (config) {
                config || (config = {});

                if (Y.Lang.isString(config.viewType)) {
                    this.viewType = Y.Object.getValue(Y, config.viewType.split('.'));
                }

                this.after('containerChange', this._afterContainerChange);
                this.after('modelChange', this._afterModelChange);
                this.after('viewChange', this._afterViewChange);

                this.get('model').addTarget(this);
                this.get('view').addTarget(this);
            },

            destroy: function () {
                var model = this.get('model'),
                    view  = this.get('view');

                model.destroy.apply(model, arguments);
                view.destroy.apply(view, arguments);

                return Y.Presenter.superclass.destroy.apply(this, arguments);
            },

            remove: function () {
                var view = this.get('view');
                view.remove.apply(view, arguments);
                return this;
            },

            render: function () {
                var view = this.get('view');
                view.render.apply(view, arguments);
                return this;
            },

            _getContainer: function () {
                return this.get('view').get('container');
            },

            _setModel: function (model) {
                if (!(model && model._isYUIModel)) {
                    model = new Y.Model(model);
                }

                return model;
            },

            _setView: function (view) {
                if (!view instanceof Y.View) {
                    view = new this.view(view);
                }

                return view;
            },

            _afterContainerChange: function (e) {
                this.get('view').set('container', e.newVal);
            },

            _afterViewChange: function (e) {
                e.prevVal && e.prevVal.removeTarget(this);
                e.newVal && e.newVal.addTarget(this);
            },

            _afterModelChange: function (e) {
                e.prevVal && e.prevVal.removeTarget(this);
                e.newVal && e.newVal.addTarget(this);
            }

        }, {
            ATTRS: {
                container: {
                    getter: '_getContainer',
                    setter: '_setContainer'
                },

                model: {
                    setter: '_setModel',
                    value : null
                },

                view: {
                    setter: '_setView',
                    value : null
                }
            }
        });

        // -- User -------------------------------------------------------------

        Y.namespace('MyApp').User = Y.Base.create('user', Y.Model, [], {
            idAttribute: 'username'
        }, {
            ATTRS: {
                fullname: {value: null},
                username: {value: null}
            }
        });

        // -- UserView -------------------------------------------------------------

        Y.namespace('MyApp').UserView = Y.Base.create('userView', Y.View, [], {
            template: Y.Handlebars.compile(Y.one('#t-user').getContent()),

            render: function () {
                var content = this.template(this.get('model').toJSON());
                this.get('container').setContent(content);
                return this;
            }
        });

        // -- UserEditView ---------------------------------------------------------

        Y.namespace('MyApp').UserEditView = Y.Base.create('userEditView', Y.View, [], {
            template: Y.Handlebars.compile(Y.one('#t-user-edit').getContent()),
            events: {
                'form'                : {submit: 'saveUser'},
                'input[name=fullname]': {change: 'updateFullname'},
                'input[name=username]': {change: 'updateUsername'}
            },

            disableUsername: function () {
                this.get('container').one('input[name=username]').set('disabled', true);
            },

            render: function () {
                var content = this.template(this.get('model').toJSON());
                this.get('container').setContent(content);
                return this;
            },

            saveUser: function (e) {
                e.preventDefault();
                this.fire('saveUser', {user: this.get('model')});
            },

            updateFullname: function (e) {
                this.fire('updateFullname', {fullname: e.target.get('value')});
            },

            updateUsername: function (e) {
                this.fire('updateUsername', {username: e.target.get('value')});
            }
        });

        // -- UserPresenter ----------------------------------------------------

        Y.namespace('MyApp').UserPresenter = Y.Base.create('userPrsenter', Y.Presenter, [], {
            initializer: function () {
                this.on('userEditView:saveUser', this.saveUser);
                this.on('userEditView:updateFullname', this.updateFullname);
                this.on('userEditView:updateUsername', this.updateUsername);
            },

            render: function () {
                Y.MyApp.UserPresenter.superclass.render.apply(this, arguments);

                if (!this.get('model').get('allowEditUsername')) {
                    this.get('view').disableUsername();
                }
            },

            saveUser: function (e) {
                var user  = e.user,
                    model = this.get('model');

                user.set('fullname', model.get('fullname'));

                if (model.get('allowEditUsername')) {
                    user.set('username', model.get('username'));
                }

                user.save();
            },

            updateFullname: function (e) {
                this.get('model').set('fullname', e.fullname);
            },

            updateUsername: function (e) {
                this.get('model').set('username', e.username);
            }
        });

        // -- App --------------------------------------------------------------

        var app;

        app = new Y.App({
            serverRouting: false,

            views: {
                show: {type: 'MyApp.UserView'},
                edit: {type: 'MyApp.UserPresenter'}
            },

            routes: [
                {path: '/',      callback: 'showUser'},
                {path: '/edit/', callback: 'editUser'}
            ]
        });

        app.showUser = function () {
            this.showView('show', {
                model: this.user
            });
        };

        app.editUser = function () {
            var user = this.user;

            // Uses a Presenter!
            this.showView('edit', {
                view : new Y.MyApp.UserEditView({model: user}),
                model: {
                    allowEditUsername: user.isNew()
                }
            });
        };

        app.user = new Y.MyApp.User({
            after: {
                save: function () {
                    app.replace('/');
                }
            }
        });

        app.render().replace('/');

    });
    </script>
</body>
</html>
